package server

import (
	"cloud-entropy-storage-system/common/pb/pbfiles"
	status2 "cloud-entropy-storage-system/server/internal/core/status"
	"context"
	"fmt"
	"time"

	grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
	"google.golang.org/grpc"
)

type VolumesHeart struct {
	connMap map[string]*grpc.ClientConn
	*pbfiles.UnimplementedVolumeHeartServer
}

func NewVolumesHeart() *VolumesHeart {
	return &VolumesHeart{connMap: make(map[string]*grpc.ClientConn)}
}

func (vh *VolumesHeart) HeartBeat(ctx context.Context, in *pbfiles.HeartRequest) (*pbfiles.HeartResponse, error) {
	var vls []*status2.VolumeStatus
	if len(in.Volumes) > 0 {
		for _, v := range in.Volumes {
			vls = append(vls, &status2.VolumeStatus{Vid: v.Id, Writable: v.Writeable, VolumeSize: v.VolumeUsed})
		}
	}
	// 获取rpc连接
	if _, ok := vh.connMap[in.Host]; !ok {
		var err error
		vh.connMap[in.Host], err = vh.getRpcConn(in.Host)
		if err != nil {
			fmt.Println(err)
		}
	}
	// 插入循环线程
	ss := &status2.StorageStatus{
		Machine:         in.Machine,
		DiskSize:        in.DiskSize,
		DiskUsed:        in.DiskUsed,
		DiskFree:        in.DiskFree,
		CanCreateVolume: in.CanCreateVolume,
		Volumes:         vls,
		Writeable:       in.Writeable,
		LastHeartbeat:   time.Now().Unix(),
		RpcConn:         vh.connMap[in.Host],
	}
	go AddStorage(ss)

	if in.VolumeNum == 0 { // todo 开关 ，需要时才打开
		return &pbfiles.HeartResponse{Code: 200, Msg: "OK", Create: true}, nil
	} else {
		return &pbfiles.HeartResponse{Code: 200, Msg: "OK", Create: false}, nil
	}
}

// rpc client
func (vh *VolumesHeart) getRpcConn(addr string) (*grpc.ClientConn, error) {
	opt := []grpc_retry.CallOption{
		grpc_retry.WithPerRetryTimeout(time.Second * 2),
		grpc_retry.WithBackoff(grpc_retry.BackoffLinearWithJitter(time.Second/2, 0.1)), // 抖动重试间隔
	}
	conn, err := grpc.Dial(addr, grpc.WithInsecure(),
		grpc.WithDefaultCallOptions(
			grpc.MaxCallRecvMsgSize(5*1024*1024*1024),
			grpc.MaxCallSendMsgSize(5*1024*1024*1024),
		), // 最大接收200MB
		grpc.WithUnaryInterceptor(grpc_retry.UnaryClientInterceptor(opt...)))
	if err != nil {
		return nil, err
	}
	return conn, nil
}
